}
Notification.prototype = {
+ IMAGE_SIZE: 125,
+
_init: function(source, title, banner, params) {
this.source = source;
this.urgency = Urgency.NORMAL;
this._titleDirection = St.TextDirection.NONE;
this._spacing = 0;
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
+ this._imageBin = null;
source.connect('destroy', Lang.bind(this,
function (source, reason) {
this._bannerBox.connect('allocate', Lang.bind(this, this._bannerBoxAllocate));
this._table.add(this._bannerBox, { row: 0,
col: 1,
+ col_span: 2,
+ x_expand: false,
y_expand: false,
y_fill: false });
+ // This is an empty cell that overlaps with this._bannerBox cell to ensure
+ // that this._bannerBox cell expands horizontally, while not forcing the
+ // this._imageBin that is also in col: 2 to expand horizontally.
+ this._table.add(new St.Bin(), { row: 0,
+ col: 2,
+ y_expand: false,
+ y_fill: false });
+
this._titleLabel = new St.Label();
this._bannerBox.add_actor(this._titleLabel);
this._bannerUrlHighlighter = new URLHighlighter();
this._actionArea = null;
this._buttonBox = null;
}
- if (!this._scrollArea && !this._actionArea)
+ if (this._imageBin && params.clear)
+ this.unsetImage();
+
+ if (!this._scrollArea && !this._actionArea && !this._imageBin)
this._table.remove_style_class_name('multi-line-notification');
this._icon = params.icon || this.source.createNotificationIcon();
vscrollbar_policy: this._scrollPolicy,
hscrollbar_policy: Gtk.PolicyType.NEVER,
style_class: 'vfade' });
- this._table.add(this._scrollArea, { row: 1, col: 1 });
+ this._table.add(this._scrollArea, { row: 1,
+ col: 2 });
+ this._updateLastColumnSettings();
this._contentArea = new St.BoxLayout({ name: 'notification-body',
vertical: true });
this._scrollArea.add_actor(this._contentArea);
if (!props)
props = {};
props.row = 2;
- props.col = 1;
+ props.col = 2;
this._table.add_style_class_name('multi-line-notification');
this._table.add(this._actionArea, props);
+ this._updateLastColumnSettings();
this._updated();
},
+ _updateLastColumnSettings: function() {
+ if (this._scrollArea)
+ this._table.child_set(this._scrollArea, { col: this._imageBin ? 2 : 1,
+ col_span: this._imageBin ? 1 : 2 });
+ if (this._actionArea)
+ this._table.child_set(this._actionArea, { col: this._imageBin ? 2 : 1,
+ col_span: this._imageBin ? 1 : 2 });
+ },
+
+ setImage: function(image) {
+ if (this._imageBin)
+ this.unsetImage();
+ this._imageBin = new St.Bin();
+ this._imageBin.child = image;
+ this._imageBin.opacity = 230;
+ this._table.add_style_class_name('notification-with-image');
+ this._updateLastColumnSettings();
+ this._table.add(this._imageBin, { row: 1,
+ col: 1,
+ row_span: 2,
+ x_expand: false,
+ y_expand: false,
+ x_fill: false,
+ y_fill: false });
+ },
+
+ unsetImage: function() {
+ if (this._imageBin) {
+ this._table.remove_style_class_name('notification-with-image');
+ this._table.remove_actor(this._imageBin);
+ this._imageBin = null;
+ this._updateLastColumnSettings();
+ }
+ },
+
// addButton:
// @id: the action ID
// @label: the label for the action's button
let box = new St.BoxLayout({ name: 'notification-actions' });
this.setActionArea(box, { x_expand: false,
+ y_expand: false,
x_fill: false,
+ y_fill: false,
x_align: St.Align.END });
this._buttonBox = box;
}
return new St.Icon({ icon_name: icon,
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
- } else if (hints['image-data']) {
- let [width, height, rowStride, hasAlpha,
- bitsPerSample, nChannels, data] = hints['image-data'];
- return textureCache.load_from_raw(data, hasAlpha,
- width, height, rowStride, size);
} else {
let stockIcon;
switch (hints.urgency) {
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
- // Be compatible with the various hints for image data
- // 'image-data' is the latest name of this hint, introduced in 1.2
- if (!hints['image-data']) {
+ // Be compatible with the various hints for image data and image path
+ // 'image-data' and 'image-path' are the latest name of these hints, introduced in 1.2
+
+ if (!hints['image-path'] && hints['image_path'])
+ hints['image-path'] = hints['image_path']; // version 1.1 of the spec
+
+ if (!hints['image-data'])
if (hints['image_data'])
hints['image-data'] = hints['image_data']; // version 1.1 of the spec
- else if (hints['icon_data'])
- hints['image-data'] = hints['icon_data']; // previous versions of the spec
- }
+ else if (hints['icon_data'] && !hints['image-path'])
+ // early versions of the spec; 'icon_data' should only be used if 'image-path' is not available
+ hints['image-data'] = hints['icon_data'];
let ndata = { appName: appName,
icon: icon,
clear: true });
}
+ if (hints['image-data'] || hints['image-path']) {
+ let image = null;
+ if (hints['image-data']) {
+ let [width, height, rowStride, hasAlpha,
+ bitsPerSample, nChannels, data] = hints['image-data'];
+ image = St.TextureCache.get_default().load_from_raw(data, hasAlpha,
+ width, height, rowStride, notification.IMAGE_SIZE);
+ } else if (hints['image-path']) {
+ image = St.TextureCache.get_default().load_uri_async(GLib.filename_to_uri(hints['image-path'], null),
+ notification.IMAGE_SIZE,
+ notification.IMAGE_SIZE);
+ }
+ notification.setImage(image);
+ } else {
+ notification.unsetImage();
+ }
+
if (actions.length) {
notification.setUseActionIcons(hints['action-icons'] == true);
for (let i = 0; i < actions.length - 1; i += 2) {